// 《围棋》作者版权所有。版权所有。
// 此源代码的使用受BSD样式
// 许可证的约束，该许可证可以在许可证文件中找到。

package bufio

import (
	"bytes"
	"errors"
	"io"
	"unicode/utf8"
)

// 扫描仪提供了一个方便的接口，用于读取数据，例如
// 一个由换行符分隔的文本行组成的文件。连续调用
// Scan方法将逐步遍历文件的“令牌”，跳过
// 令牌之间的字节。令牌的规范为
// 由SplitFunc类型的拆分函数定义；默认的split 
// 函数将输入拆分为行，并去除行终止符。Split 
// 函数在这个包中定义，用于将文件扫描为
// 行、字节、UTF-8编码的符码和空格分隔的字。
// 客户端可能会提供自定义拆分功能。
// 
// 扫描在EOF、第一个I/O错误或令牌太大无法放入缓冲区时无法恢复。当扫描停止时，读卡器的
// 可能已经超过了最后一个标记。需要更多
// 控制错误处理或大型令牌的程序，或者必须在读卡器上运行顺序扫描
// 的程序，应该使用bufio。读者。
// 
type Scanner struct {
	r            io.Reader // 客户提供的阅读器。
	split        SplitFunc // 分割令牌的函数。
	maxTokenSize int       // 令牌的最大大小；通过测试进行修改。
	token        []byte    // 拆分返回的最后一个令牌。
	buf          []byte    // 缓冲区用作拆分参数。
	start        int       // buf中的第一个未处理字节。
	end          int       // buf中的数据结束。
	err          error     // 粘性错误。
	empties      int       // 连续空令牌的计数。
	scanCalled   bool      // 已调用扫描；缓冲区正在使用中。
	done         bool      // 扫描已完成。
}

// SplitFunc是用于标记
// 输入的split函数的签名。参数是剩余未处理
// 数据的初始子字符串，以及一个标记atEOF，用于报告读取器是否没有更多
// 数据可供提供。返回值是将输入
// 提前的字节数，以及返回给用户的下一个令牌（如果有），以及错误（如果有）。
// 
// 如果函数返回错误，扫描将停止，在这种情况下，部分
// 输入可能会被丢弃。如果该错误为ErrFinalToken，则扫描
// 将停止，且无错误。
// 
// 否则，扫描仪将推进输入。如果令牌不是nil，则
// 扫描程序将其返回给用户。如果令牌为nil，则
// 扫描仪读取更多数据并继续扫描；如果没有更多的
// 数据——如果atEOF为真——扫描仪将返回。如果数据没有
// 但仍保留完整的令牌，例如，当
// 扫描行时，如果数据没有换行符，SplitFunc可以返回（0，nil，nil）以通知
// 扫描仪将更多数据读取到该切片中，然后使用
// 从输入的同一点开始的更长切片重试。
// 
// 除非atEOF 
// 为真，否则永远不会使用空数据片调用该函数。但是，如果atEOF为真，则数据可能不是空的，并且
// 一如既往地保存未处理的文本。
type SplitFunc func(data []byte, atEOF bool) (advance int, token []byte, err error)

// 扫描仪返回错误。
var (
	ErrTooLong         = errors.New("bufio.Scanner: token too long")
	ErrNegativeAdvance = errors.New("bufio.Scanner: SplitFunc returns negative advance count")
	ErrAdvanceTooFar   = errors.New("bufio.Scanner: SplitFunc returns advance count beyond input")
	ErrBadReadCount    = errors.New("bufio.Scanner: Read returned impossible count")
)

const (
	// MaxScanTokenSize是用于缓冲令牌的最大大小
	// 除非用户使用扫描仪提供显式缓冲区。缓冲器
	// 实际最大令牌大小可能更小，因为缓冲区
	// 可能需要包括，例如，换行符。
	MaxScanTokenSize = 64 * 1024

	startBufSize = 4096 // 缓冲区初始分配的大小。
)

// NewScanner返回一个新的扫描器以从r中读取。
// 拆分函数默认为扫描线。
func NewScanner(r io.Reader) *Scanner {
	return &Scanner{
		r:            r,
		split:        ScanLines,
		maxTokenSize: MaxScanTokenSize,
	}
}

// Err返回扫描仪遇到的第一个非EOF错误。
func (s *Scanner) Err() error {
	if s.err == io.EOF {
		return nil
	}
	return s.err
}

// Bytes返回调用扫描生成的最新令牌。
// 基础数组可能指向将被后续扫描调用覆盖的数据。它不进行分配。
func (s *Scanner) Bytes() []byte {
	return s.token
}

// Text将调用扫描
// 生成的最新令牌作为新分配的字符串返回，该字符串保存其字节。
func (s *Scanner) Text() string {
	return string(s.token)
}

// ErrFinalToken是一个特殊的哨兵错误值。Split函数返回的是
// 表示正在传递的令牌
// 有错误的是最后一个令牌，扫描应该在这一个令牌之后停止。
// 扫描收到ErrFinalToken后，扫描停止，没有错误。
// 该值有助于提前停止处理，或在需要
// 传递最终的空令牌时停止处理。使用自定义错误值可以实现相同的行为
// 但是在这里提供一个更整洁。
// 有关此值的用法，请参见emptyFinalToken示例。
var ErrFinalToken = errors.New("final token")

// 扫描将扫描器前进到下一个令牌，该令牌将是
// 可通过字节或文本方法获得。当
// 扫描到达输入端或出现错误而停止时，返回false。
// 扫描返回false后，Err方法将返回扫描期间发生的任何错误，除非是io。EOF，Err 
// 将返回零。
// 如果split函数返回太多空的
// 标记而不推进输入，则扫描恐慌。这是
// 扫描仪的常见错误模式。
func (s *Scanner) Scan() bool {
	if s.done {
		return false
	}
	s.scanCalled = true
	// 循环，直到我们有令牌。
	for {
		// 看看我们能不能用现有的东西得到一个代币。
		// 如果数据用完但出现错误，请给分割函数
		// 一个机会来恢复任何剩余的，可能是空的令牌。
		if s.end > s.start || s.err != nil {
			advance, token, err := s.split(s.buf[s.start:s.end], s.err != nil)
			if err != nil {
				if err == ErrFinalToken {
					s.token = token
					s.done = true
					return true
				}
				s.setErr(err)
				return false
			}
			if !s.advance(advance) {
				return false
			}
			s.token = token
			if token != nil {
				if s.err == nil || advance > 0 {
					s.empties = 0
				} else {
					// 返回令牌，而不是在EOF上推进输入。
					s.empties++
					if s.empties > maxConsecutiveEmptyReads {
						panic("bufio.Scan: too many empty tokens without progressing")
					}
				}
				return true
			}
		}
		// 我们不能用我们持有的东西生成令牌。
		// 如果我们已经遇到EOF或I/O错误，我们就完成了。
		if s.err != nil {
			// 关闭它。
			s.start = 0
			s.end = 0
			return false
		}
		// 必须读取更多数据。
		// 首先，如果有大量的空空间
		// 或者需要空间，请将数据转移到缓冲区的开头。
		if s.start > 0 && (s.end == len(s.buf) || s.start > len(s.buf)/2) {
			copy(s.buf, s.buf[s.start:s.end])
			s.end -= s.start
			s.start = 0
		}
		// 缓冲区已满吗？如果是，请调整大小。
		if s.end == len(s.buf) {
			// 保证下面的乘法中没有溢出。
			const maxInt = int(^uint(0) >> 1)
			if len(s.buf) >= s.maxTokenSize || len(s.buf) > maxInt/2 {
				s.setErr(ErrTooLong)
				return false
			}
			newSize := len(s.buf) * 2
			if newSize == 0 {
				newSize = startBufSize
			}
			if newSize > s.maxTokenSize {
				newSize = s.maxTokenSize
			}
			newBuf := make([]byte, newSize)
			copy(newBuf, s.buf[s.start:s.end])
			s.buf = newBuf
			s.end -= s.start
			s.start = 0
		}
		// 最后我们可以读取一些输入。确保我们不会被一个行为不端的读者困住。官方上我们不需要这样做，但让我们更加小心：扫描仪是用于安全、简单的工作。
		for loop := 0; ; {
			n, err := s.r.Read(s.buf[s.end:len(s.buf)])
			if n < 0 || len(s.buf)-s.end < n {
				s.setErr(ErrBadReadCount)
				break
			}
			s.end += n
			if err != nil {
				s.setErr(err)
				break
			}
			if n > 0 {
				s.empties = 0
				break
			}
			loop++
			if loop > maxConsecutiveEmptyReads {
				s.setErr(io.ErrNoProgress)
				break
			}
		}
	}
}

// advance消耗n字节的缓冲区。它报告了这笔预付款是否合法。
func (s *Scanner) advance(n int) bool {
	if n < 0 {
		s.setErr(ErrNegativeAdvance)
		return false
	}
	if n > s.end-s.start {
		s.setErr(ErrAdvanceTooFar)
		return false
	}
	s.start += n
	return true
}

// setErr记录遇到的第一个错误。
func (s *Scanner) setErr(err error) {
	if s.err == nil || s.err == io.EOF {
		s.err = err
	}
}

// Buffer设置扫描时使用的初始缓冲区，以及扫描期间可能分配的最大
// 缓冲区大小。最大
// 令牌大小是最大值和上限（buf）中的较大值。如果max<=cap（buf），
// 扫描将仅使用此缓冲区，不进行分配。默认情况下，Scan使用内部缓冲区并将最大令牌大小设置为MaxScanTokenSize。
// 
// 如果在扫描开始后调用缓冲区，缓冲区会出现死机。
func (s *Scanner) Buffer(buf []byte, max int) {
	if s.scanCalled {
		panic("Buffer called after Scan")
	}
	s.buf = buf[0:cap(buf)]
	s.maxTokenSize = max
}

// Split设置扫描仪的拆分功能。
// 默认拆分函数为扫描线。
// 
// 如果在扫描开始后调用，则拆分恐慌。
func (s *Scanner) Split(split SplitFunc) {
	if s.scanCalled {
		panic("Split called after Scan")
	}
	s.split = split
}

// 拆分函数

// ScanBytes是一个用于扫描仪的拆分函数，它将每个字节作为令牌返回。
func ScanBytes(data []byte, atEOF bool) (advance int, token []byte, err error) {
	if atEOF && len(data) == 0 {
		return 0, nil, nil
	}
	return 1, data[0:1], nil
}

var errorRune = []byte(string(utf8.RuneError))

// ScanRunes是扫描仪的拆分函数，它将每个
// UTF-8编码的rune作为令牌返回。返回的符文序列是
// 相当于以字符串形式从输入上的范围循环返回的符文序列，这意味着错误的UTF-8编码将转换为U+FFFD=“\xef\xbf\xbd”。
// 由于扫描接口，这使得客户端无法区分正确编码的替换符文和编码错误。
func ScanRunes(data []byte, atEOF bool) (advance int, token []byte, err error) {
	if atEOF && len(data) == 0 {
		return 0, nil, nil
	}

	// 快速路径1:ASCII。
	if data[0] < utf8.RuneSelf {
		return 1, data[0:1], nil
	}

	// 快速路径2：正确的UTF-8解码，无错误。
	_, width := utf8.DecodeRune(data)
	if width > 1 {
		// 这是一个有效的编码。对于正确编码的
		// 非ASCII符文，宽度不能为1。
		return width, data[0:width], nil
	}

	// 我们知道这是一个错误：我们的宽度=1，并且隐式地r==utf8。RuneError。
	// 错误是因为没有完整的符文需要解码吗？
	// FullRune正确区分错误编码和不完整编码。
	if !atEOF && !utf8.FullRune(data) {
		// 不完整；获取更多字节。
		return 0, nil, nil
	}

	// 我们有一个真正的UTF-8编码错误。返回正确编码的错误符文
	// 但只前进一个字节。这与
	// 一个编码错误的字符串上的范围循环的行为相匹配。
	return 1, errorRune, nil
}

// dropCR从数据中删除一个终端。
func dropCR(data []byte) []byte {
	if len(data) > 0 && data[len(data)-1] == '\r' {
		return data[0 : len(data)-1]
	}
	return data
}

// ScanLines是一个用于扫描仪的拆分函数，它返回每行
// 文本，去掉任何行尾标记。返回的行
// 可能为空。行尾标记是一个可选的回车符，后跟一条强制换行符
// 。在正则表达式表示法中，它是`\r？\n`。
// 即使没有
// 新线。
func ScanLines(data []byte, atEOF bool) (advance int, token []byte, err error) {
	if atEOF && len(data) == 0 {
		return 0, nil, nil
	}
	if i := bytes.IndexByte(data, '\n'); i >= 0 {
		// 我们有一个完整的换行终止行。
		return i + 1, dropCR(data[0:i]), nil
	}
	// 如果我们在EOF，我们有一条最终的、未终止的线路。还我。
	if atEOF {
		return len(data), dropCR(data), nil
	}
	// 请求更多数据。
	return 0, nil, nil
}

// isSpace报告字符是否为Unicode空白字符。
// 我们避免了对unicode包的依赖，但在测试中检查了实现的有效性。
func isSpace(r rune) bool {
	if r <= '\u00FF' {
		// 明显的ASCII码：\t通过\r加空格。再加上两个拉丁语1的怪胎。
		switch r {
		case ' ', '\t', '\n', '\v', '\f', '\r':
			return true
		case '\u0085', '\u00A0':
			return true
		}
		return false
	}
	// 高价值的。
	if '\u2000' <= r && r <= '\u200a' {
		return true
	}
	switch r {
	case '\u1680', '\u2028', '\u2029', '\u202f', '\u205f', '\u3000':
		return true
	}
	return false
}

// ScanWords是一个用于扫描仪的拆分函数，它返回文本中每个以空格分隔的单词，并删除周围的空格。它将
// 永远不会返回空字符串。空间的定义由
// unicode设置。IsSpace。
func ScanWords(data []byte, atEOF bool) (advance int, token []byte, err error) {
	// 跳过前导空格。
	start := 0
	for width := 0; start < len(data); start += width {
		var r rune
		r, width = utf8.DecodeRune(data[start:])
		if !isSpace(r) {
			break
		}
	}
	// 扫描到空格，标记单词的结尾。
	for width, i := 0, start; i < len(data); i += width {
		var r rune
		r, width = utf8.DecodeRune(data[i:])
		if isSpace(r) {
			return i + width, data[start:i], nil
		}
	}
	// 如果我们在EOF，我们有一个最终的、非空的、非终止的单词。还我。
	if atEOF && len(data) > start {
		return len(data), data[start:], nil
	}
	// 请求更多数据。
	return start, nil, nil
}
